package cn.willbj.brief.jol;

import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.HashMap;

/**
 * Copyright: Copyright (c) 2020 北京海顿中科技术有限公司
 *
 * @author zhangliuwei
 * @version 3.0.21.20200930-tzsh
 * @description
 * 最近需求，打算再内存缓存数据，数据量130000万并且还会增加，了解这些数据占用空间的大小是很常见的监控需要。
 * 常规方式，人工可以按照Java基础数据类型大小及内容大小估算出缓存对象的大概堆占用，但是麻烦还不准。
 * OpenJDK，提供了JOL包，可以帮我们在运行时计算某个对象的大小，是非常好的工具
 * 官网：http://openjdk.java.net/projects/code-tools/jol/
 * 定位：分析对象在JVM的大小和分布
 * @date 2020/10/21
 */

/**
 * # Running 64-bit HotSpot VM.
 * # Using compressed oop with 3-bit shift.
 * # Using compressed klass with 3-bit shift.
 * # Objects are 8 bytes aligned.
 * # Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
 * # Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
 *
 * cn.willbj.brief.jol.Vo object internals:
 *  OFFSET  SIZE               TYPE DESCRIPTION                               VALUE
 *       0    12                    (object header)                           N/A
 *      12     4                int Vo.a                                      N/A
 *      16     8               long Vo.b                                      N/A
 *      24     4                int Vo.e                                      N/A
 *      28     1            boolean Vo.i                                      N/A
 *      29     3                    (alignment/padding gap)
 *      32     4   java.lang.String Vo.c                                      N/A
 *      36     4   java.lang.Object Vo.d                                      N/A
 *      40     4   java.lang.Object Vo.h                                      N/A
 *      44     4                    (loss due to the next object alignment)
 * Instance size: 48 bytes
 * Space losses: 3 bytes internal + 4 bytes external = 7 bytes total
 *
 * =================
 * aoffset=12
 * va=2
 *
 * Process finished with exit code 0
 */
public class Vo {
        public int a = 0;
        public long b = 0;
        public String c= "123";
        public Object d= null;
        public int e = 100;
        public static int f= 0;
        public static String g= "";
        public Object h= null;
        public boolean i;

    public static void main(String[] args) throws Exception {
         System.out.println(VM.current().details());
        System.out.println(ClassLayout.parseClass(Vo.class).toPrintable());
        System.out.println("=================");
        Unsafe unsafe = getUnsafeInstance();
        Vo vo = new Vo();
        vo.a=2;
        vo.b=3;
        vo.d=new HashMap<>();
        long aoffset = unsafe.objectFieldOffset(Vo.class.getDeclaredField("a"));
        System.out.println("aoffset="+aoffset);
        // 获取a的值
        int va = unsafe.getInt(vo, aoffset);
        System.out.println("va="+va);
    }

    public static Unsafe getUnsafeInstance() throws Exception {
        // 通过反射获取rt.jar下的Unsafe类
        Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafeInstance.setAccessible(true);
        // return (Unsafe) theUnsafeInstance.get(null);是等价的
        return (Unsafe) theUnsafeInstance.get(Unsafe.class);
    }

}
